圖片來源:https://artprojectsforkids.org/how-to-draw-a-dolphin/
請注意,透過 Flipper Zero 學習的資訊技術與知識,目的在於提升個人的技術能力和資安意識。我們強烈呼籲大家,絕對不要使用所學知識從事任何違法行為。您的合法使用是我們的期望,也是您自身責任的
一部分。
我們要繼續提到 SceneManager 透過一系列的 scene_manager_*
開頭的函式來管理應用程式中的所有場景細節。主要是確保當進入場景、離開場景或接收到新事件時,相關的處理函式會被正確的呼叫。
另一個是 ViewDispatcher 是使用許多 view_dispatcher_*
的函式來管理 views。這些函式會在 SceneManager 中被呼叫。總之,ViewDispatcher 是負責處理場景中 Views 的顯示和管理。
當我們在定義應用程式場景時,應提供所有場景處理函式作為一個 SceneManagerHandlers 結構傳給 scene_manager_alloc
函式。例如說作者這邊的場景會用數字做為索引,同時為了方便追蹤這些場景,通常我們會定義一個 enum 類型來表示場景的索引,像是:
typedef enum {
TestAppScene_MainMenu, // 主選單場景
TestAppScene_FirstPopup, // 第一個彈出視窗場景
TestAppScene_SecondPopup, // 第二個彈出視窗場景
TestAppScene_count // 場景計數,方便後續擴展
} TestAppScene;
像是這邊的 count 只要放在枚舉的最後一項,之後增加或是修改場景數量的時候都可以輕鬆算出場景的總數。
而視圖是可以重複使用的,因此應用程式中可能場景數量會比視圖更多。換句話說,我們有可能一個視圖對應多個場景:
typedef enum {
TestAppView_Menu, // 菜單視圖
TestAppView_Popup // 彈出視圖
} TestAppScene;
這樣也提高了資源利用率。
首先我們會在 test_app_init
函式裡面初始化 scene manager 以及 view dispatcher:
TestApp* app = malloc(sizeof(TestApp));
test_app_scene_manager_init(app);
test_app_view_dispatcher_init(app);
app->scene_manager = scene_manager_alloc(&test_app_scene_event_handlers, app);
我們為 SceneManager 分配記憶體。
其中這邊的第二個參數是 context,當場景處理方法被調用時,會回傳這個 context,第一個參數是 SceneManagerHandlers* test_app_scene_event_handlers
已經提前定義好並包含 on_enter
、on_exit
、on_event
處理函式集合。
on_enter_handlers
:當進入某個場景時會調用這個處理函式集合,它包含了所有場景的進入處理邏輯。這些函式與定義的 enum 順序一致。例如,進入主選單或彈出視窗時會調用對應的進入函數。
void (*const test_app_scene_on_enter_handlers[])(void*) = {
test_app_scene_on_enter_main_menu,
test_app_scene_on_enter_popup_one,
test_app_scene_on_enter_popup_two};
on_event_handlers
:當某個場景處於活動狀態時,並且收到了事件(如使用者操作),會調用這個事件處理函式集合。每個場景有其專屬的事件處理邏輯,也是與 enum 順序一致。
bool (*const test_app_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
test_app_scene_on_event_main_menu,
test_app_scene_on_event_popup_one,
test_app_scene_on_event_popup_two};
on_exit_handlers
:當離開某個場景時,會調用這個處理函式集合。這些函式負責處理場景退出時的清理或其他工作,同樣是與 enum 順序保持一致。
void (*const test_app_scene_on_exit_handlers[])(void*) = {
test_app_scene_on_exit_main_menu,
test_app_scene_on_exit_popup_one,
test_app_scene_on_exit_popup_two};
test_app_scene_event_handlers
:這是所有場景處理器的集合,包含 on_enter
、on_event
和 on_exit
的處理函數。這樣的結構可以確保每個場景的進入、事件處理和退出邏輯都能正確運行。
const SceneManagerHandlers test_app_scene_event_handlers = {
.on_enter_handlers = test_app_scene_on_enter_handlers, // 進入處理函式集合
.on_event_handlers = test_app_scene_on_event_handlers, // 事件處理函式集合
.on_exit_handlers = test_app_scene_on_exit_handlers, // 退出處理函式集合
.scene_num = TestAppScene_count}; // 場景數量
test_app_view_dispatcher_init
函式負責初始化視圖分發器,這部分稍微複雜一點。具體的步驟如下:
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
app->menu = menu_alloc();
app->popup = popup_alloc();
// 設置回調函式,將事件從視圖傳遞到場景管理器
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher,
test_app_scene_manager_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher,
test_app_scene_manager_navigation_event_callback);
// 將視圖添加到分發器,並根據它們的列舉值進行索引
view_dispatcher_add_view(
app->view_dispatcher,
TestAppView_Menu,
menu_get_view(app->menu));
view_dispatcher_add_view(
app->view_dispatcher,
TestAppView_Popup,
popup_get_view(app->popup));
今天就先到這邊,預計明天走完教學,後天做出自已的 app。
各位明天見!